package com.mrinalwadhwa.primitives
{
    import flash.display.Graphics;

    import spark.primitives.supportClasses.FilledElement;



    public class EllipticalArc extends FilledElement
    {

        //--------------------------------------------------------------------------
        //
        // 	Constructor  
        //
        //--------------------------------------------------------------------------


        /**
         *  Constructor.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10
         *  @playerversion AIR 1.5
         *  @productversion Flex 4
         */
        public function EllipticalArc()
        {
            super();
        }


        //--------------------------------------------------------------------------
        //
        // 	Properties  
        //
        //--------------------------------------------------------------------------


        //-----------------------
        //  startAngle	  
        //-----------------------

        private var _startAngle:Number;

        /**
         *  The beginning angle of the arc. If not specified
         *  a default value of 0 is used.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10
         *  @playerversion AIR 1.5
         *  @productversion Flex 4
         */
        public function get startAngle():Number
        {
            if (!_startAngle)
            {
                return 0;
            }
            return _startAngle;
        }

        /**
         *  @private
         */
        public function set startAngle(value:Number):void
        {
            if (_startAngle != value)
            {
                _startAngle = value;

                invalidateSize();
                invalidateDisplayList();
                invalidateParentSizeAndDisplayList();
            }
        }



        //-----------------------
        //  arc	  
        //-----------------------

        private var _arc:Number;

        /**
         *  The angular extent of the arc. If not specified
         *  a default value of 0 is used.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10
         *  @playerversion AIR 1.5
         *  @productversion Flex 4
         */
        public function get arc():Number
        {
            if (!_arc)
            {
                return 0;
            }
            return _arc;
        }

        /**
         *  @private
         */
        public function set arc(value:Number):void
        {
            if (_arc != value)
            {
                _arc = value;

                invalidateSize();
                invalidateDisplayList();
                invalidateParentSizeAndDisplayList();
            }
        }



        //-----------------------
        //  closureType	  
        //-----------------------

        private var _closureType:String;

        [Inspectable(category="General",enumeration="open,chord,pie",defaultValue="open")]

        /**
         * The method in which to close the arc.
         * <p>
         * <li><b>open</b> will apply no closure.</li>
         * <li><b>chord</b> will close the arc with a strait line to the start.</li>
         * <li><b>pie</b> will draw a line from center to start and end to center forming a pie shape.</li>
         * </p>
         **/
        public function get closureType():String
        {
            if (!_closureType)
            {
                return "open";
            }
            return _closureType;
        }

        public function set closureType(value:String):void
        {
            if (_closureType != value)
            {
                _closureType = value;

                invalidateSize();
                invalidateDisplayList();
                invalidateParentSizeAndDisplayList();
            }
        }






        //--------------------------------------------------------------------------
        //
        //  Overridden methods
        //
        //--------------------------------------------------------------------------

        /**
         *  @inheritDoc
         *
         *  @langversion 3.0
         *  @playerversion Flash 10
         *  @playerversion AIR 1.5
         *  @productversion Flex 4
         */
        override protected function draw(g:Graphics):void
        {
            var newX:Number = (width / 2) + (width / 2) * Math.cos(startAngle * (Math.PI / 180)) + x;
            var newY:Number = (height / 2) - (height / 2) * Math.sin(startAngle * (Math.PI / 180)) + y;

            var ax:Number;
            var ay:Number;

            //draw the start line in the case of a pie type
            if (closureType == "pie")
            {
                ax = newX - Math.cos(-(startAngle / 180) * Math.PI) * width / 2;
                ay = newY - Math.sin(-(startAngle / 180) * Math.PI) * height / 2;

                if (Math.abs(arc) < 360)
                {
                    g.moveTo(ax, ay);
                    g.lineTo(newX, newY);
                }
            }

            g.moveTo(newX, newY);
            drawEllipticalArc(newX, newY, startAngle, arc, (width * 0.5), (height * 0.5), g);


            //close the arc if required
            if (Math.abs(arc) < 360)
            {
                if (closureType == "pie")
                {
                    g.lineTo(ax, ay);
                }

                if (closureType == "chord")
                {
                    g.lineTo(newX, newY);
                }
            }

        }



        /**
         *  @private
         */
        protected static function drawEllipticalArc(x:Number, y:Number, startAngle:Number, arc:Number, radius:Number,
                                                    yRadius:Number, g:Graphics):void
        {

            var ax:Number;
            var ay:Number;

            // Circumvent drawing more than is needed
            if (Math.abs(arc) > 360)
            {
                arc = 360;
            }

            // Draw in a maximum of 45 degree segments. First we calculate how many 
            // segments are needed for our arc.
            var segs:Number = Math.ceil(Math.abs(arc) / 45);

            // Now calculate the sweep of each segment
            var segAngle:Number = arc / segs;

            // The math requires radians rather than degrees. To convert from degrees
            // use the formula (degrees/180)*Math.PI to get radians. 
            var theta:Number = -(segAngle / 180) * Math.PI;

            // convert angle startAngle to radians
            var angle:Number = -(startAngle / 180) * Math.PI;

            // find our starting points (ax,ay) relative to the secified x,y
            ax = x - Math.cos(angle) * radius;
            ay = y - Math.sin(angle) * yRadius;

            // Draw as 45 degree segments
            if (segs > 0)
            {
                var oldX:Number = x;
                var oldY:Number = y;
                var cx:Number;
                var cy:Number;
                var x1:Number;
                var y1:Number;

                // Loop for drawing arc segments
                for (var i:int = 0; i < segs; i++)
                {

                    // increment our angle
                    angle += theta;

                    //find the angle halfway between the last angle and the new one,
                    //calculate our end point, our control point, and draw the arc segment

                    cx = ax + Math.cos(angle - (theta / 2)) * (radius / Math.cos(theta / 2));

                    cy = ay + Math.sin(angle - (theta / 2)) * (yRadius / Math.cos(theta / 2));

                    x1 = ax + Math.cos(angle) * radius;

                    y1 = ay + Math.sin(angle) * yRadius;


                    g.curveTo(cx, cy, x1, y1);

                    oldX = x1;
                    oldY = y1;
                }
            }
        }

    }
}